﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Collections.ObjectModel;
using System.Windows.Media.Imaging;

namespace FaceDesktopTagger
{
    class FileTagger
    {
        private String m_filename;
        public FileTagger(String fileName)
        {
            m_filename = fileName;
        }
        public void AddTag(String tag)
        {
            if (m_filename.EndsWith(".jpg", true, null))
                AddTagJpeg(tag);
        }
        private void AddTagJpeg(String tag)
        {
            
            FileStream fs = new FileStream(m_filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
            JpegBitmapDecoder jpgDecoder = new JpegBitmapDecoder(fs, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
            InPlaceBitmapMetadataWriter mdWriter;
            int keywordsCount=0;
            if (jpgDecoder.Frames[0].Metadata == null)
            {
                //File needs to be close be cause the tag will be added to a different file
                fs.Close();
                fs.Dispose(); //Verify if dispose is needed after close
                AddXMPMetaData();
            }
            else
            {

                mdWriter = jpgDecoder.Frames[0].CreateInPlaceBitmapMetadataWriter();
               
                if (mdWriter.Keywords == null)
                {
                    //File needs to be close be cause the tag will be added to a different file
                    fs.Close();
                    fs.Dispose(); //Verify if dispose is needed after close
                    //Make sure the we have enough space for current tag and future tags
                    AddXMPMetaData();
                    //Reopen file
                    fs = new FileStream(m_filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
                    jpgDecoder = new JpegBitmapDecoder(fs, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
                   
                }
                else
                    keywordsCount = mdWriter.Keywords.Count;
            }

            mdWriter = jpgDecoder.Frames[0].CreateInPlaceBitmapMetadataWriter();
            //Add Tag
            mdWriter.SetQuery("/xmp/dc:subject/{int=" + keywordsCount + "}", tag);
            mdWriter.TrySave();
            fs.Close();
            fs.Dispose();


        }

        private void AddXMPMetaData()
        {
            FileStream fs = new FileStream(m_filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
            JpegBitmapDecoder jpgDecoder = new JpegBitmapDecoder(fs, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);

            BitmapMetadata metadata;
            JpegBitmapEncoder jpgEncoder = new JpegBitmapEncoder();
            if (jpgDecoder.Frames[0].Metadata == null)
            {
                metadata = new BitmapMetadata("jpeg");
            }

            else
            {
                metadata = jpgDecoder.Frames[0].Metadata.Clone() as BitmapMetadata;
            }

            metadata.SetQuery("/app1/ifd/PaddingSchema:Padding", (uint)4096);
            metadata.SetQuery("/app1/ifd/exif/PaddingSchema:Padding", (uint)4096);
            metadata.SetQuery("/xmp/PaddingSchema:Padding", (uint)4096);
            //Add container
            metadata.SetQuery("/xmp/dc:subject", new BitmapMetadata("xmpbag"));

            jpgEncoder.Frames.Add(BitmapFrame.Create(jpgDecoder.Frames[0], jpgDecoder.Frames[0].Thumbnail, metadata, jpgDecoder.Frames[0].ColorContexts));

            using (Stream tempStream = File.Open(m_filename + ".tmp", FileMode.Create, FileAccess.ReadWrite))
            {
                jpgEncoder.Save(tempStream);
            }

         
            fs.Close();

            //TODO: Verify that file was really saved before deleting it!!! (Check MD5 sum maybe?)
            File.Delete(m_filename);
            File.Move(m_filename + ".tmp", m_filename);
        }
    
    }
}
